#!/usr/bin/perl
#
# $Id$ 
#
# Eliminate CPP condional compilation for different kernel version, i.e.
# eliminate all occurences of #if LINUX_VERSION_CODE < KERNEL_VERSION(...)
# and likewise for <=, >, and >=.
#
# Call as kv [-d] <version> <file> where <version> is the kernel version you
# want the code to be generated for, in the form <major>.<minor>.<patchlevel>.
# The -d (debug) option will give you some output on what the program does.
# The result will be output on stdout.

require("getopts.pl");

$re = "^\\#if LINUX_VERSION_CODE (<|<=|>|>=) " .
    "KERNEL_VERSION\\((\\d+),(\\d+),(\\d+)\\)";

Getopts("d");
$debug = $opt_d;

$version = shift;
$level   = 0;
$state   = -1;

@lines = <>;
unshift(@lines, "");

for ($i = 1; $i <= $#lines; $i++) {
    printf("%6d: ", $i) if ($debug);
    $_ = $lines[$i];
    if ($state == -1) {
	if (/$re/) {
	    $state = compare($version, $1, $2, $3, $4);
	    print "<del>\n" if ($debug);
	    $skip = ($lines[$i-1] eq "\n");
	} else {
	    print;
	}
    } else {
	if ($level == 0 && /^\#else/) {
	    $state = !$state;
	    print "<del>\n" if ($debug);
	} elsif ($level == 0 && /^\#endif/) {
	    $state = -1;
	    print "<del>\n" if ($debug);

	    while ($skip && $lines[$i+1] eq "\n") {
		$i++;
		printf("%6d: <skip>\n", $i) if ($debug);
	    }
	} elsif (/^\#if/) {
	    $level++;
	    print "<del>\n" if ($debug);
	} elsif (/^\#endif/) {
	    $level--;
	    print "<del>\n" if ($debug);
	} elsif ($state == 1) {
	    print;
	    $skip = 0;
	} else {
	    print "<del>\n" if ($debug);
	}
    }
}

sub compare() {
    ($version, $op, $major, $minor, $patchlevel) = @_;

    ($mj, $mn, $pl) = split(/\./, $version);
    
    if ($op eq "<" &&
	($mj < $major ||
	 $mj == $major && ($mn < $minor || 
			   $mn == $minor && $pl < $patchlevel))) {
	return 1;
    } elsif ($op eq "<=" &&
	     ($mj < $major ||
	      $mj == $major && ($mn < $minor || 
				$mn == $minor && $pl <= $patchlevel))) {
	return 1;
    } elsif ($op eq ">" &&
	     ($mj > $major ||
	      $mj == $major && ($mn > $minor || 
				$mn == $minor && $pl > $patchlevel))) {
	return 1;
    } elsif ($op eq ">=" &&
	     ($mj > $major ||
	      $mj == $major && ($mn > $minor || 
				$mn == $minor && $pl >= $patchlevel))) {
	return 1;
    } else {
	return 0;
    }
}
